package com.liziba.es.servic;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.liziba.es.JDSearchApplication;
import com.liziba.es.pojo.SearchContent;
import com.liziba.es.util.ElasticsearchUtil;
import com.liziba.es.util.HtmlParseUtil;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @auther LiZiBa
 * @date 2021/2/26 0:38
 * @description:
 **/

@Service
@RequiredArgsConstructor
public class SearchContentService {

    @NonNull
    private RestHighLevelClient client;

    /**
     * 批量存储获取的京东数据
     * @param searchKey
     * @return
     * @throws IOException
     */
    public boolean parseSearchContent(String searchKey) throws IOException {

        ElasticsearchUtil elasticsearchUtil = new ElasticsearchUtil(client);
        // 根据关键字爬取数据
        List<SearchContent> searchContents = HtmlParseUtil.parseJDSearchContent(searchKey);
        // 转成JSONObject
        List<JSONObject> collect = searchContents.stream().map(JSONUtil::parseObj).collect(Collectors.toList());
        // 批量保存到elasticsearch
        return elasticsearchUtil.bulkDocument(JDSearchApplication.INDEX_NAME, collect);
    }


    /**
     * 根据关键字分页查询
     * @param pageNum           查询起始页
     * @param pageSize          每页大小
     * @param searchKey         查询关键字
     * @return
     * @throws IOException
     */
    public List<Map<String, Object>> page(Integer pageNum, Integer pageSize, String searchKey) throws IOException {
        if (pageNum <=0) {
            pageNum = 1;
        }

        SearchRequest request = new SearchRequest(JDSearchApplication.INDEX_NAME);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        // 分页
        builder.from(pageNum);
        builder.size(pageSize);

        // 字段查询
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", searchKey);
        builder.query(termQueryBuilder);
        builder.timeout(TimeValue.timeValueSeconds(30));

        // 高亮查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name");
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        highlightBuilder.requireFieldMatch(false);
        builder.highlighter(highlightBuilder);

        // 请求elasticsearch
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        List<Map<String, Object>> searchResponse = new ArrayList<>(response.getHits().getHits().length);
        // name字段值替换为高亮值
        for (SearchHit hit : response.getHits().getHits()) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField name = highlightFields.get("name");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            if (name != null) {
                Text[] fragments = name.getFragments();
                StringBuilder sb = new StringBuilder();
                for (Text fragment : fragments) {
                    sb.append(fragment);
                }
                sourceAsMap.put("name", sb.toString());
            }
            searchResponse.add(sourceAsMap);
        }
        return searchResponse;
    }
}
